package com.zyb.ext.ioc;

import com.zyb.ext.ioc.annotate.ExtResourceAnnotation;
import com.zyb.ext.ioc.utils.ClazzUtils;
import com.zyb.ext.ioc.annotate.ExtServiceAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注解版本IOC实现
 */
@Slf4j
public class MyIocForAnnotate {

    //key:beanId,value:beanId对应的对象
    private Map<String, Object> classMap = null;

    public MyIocForAnnotate(String packagePath) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        classMap = new ConcurrentHashMap<>();
        //初始化类的注入
        initBean(packagePath);
        //初始化注入类的属性 - 依赖注入
        initBeanField(classMap);
    }

    private void initBeanField(Map<String, Object> classMap) throws IllegalAccessException {
        if (classMap == null || classMap.isEmpty()) {
            throw new RuntimeException("指定的包路径下没有任何类使用了ExtServiceAnnotation注解");
        }
        for (Map.Entry<String, Object> entry : classMap.entrySet()) {
            //为类属性注入值
            setBeanField(entry.getValue());
        }

    }

    private void setBeanField(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        if (fields != null && fields.length > 0) {
            for (Field field : fields) {
                //判断注解类的属性是否加上了ExtResourceAnnotation注解
                ExtResourceAnnotation declaredAnnotation = field.getDeclaredAnnotation(ExtResourceAnnotation.class);
                if (declaredAnnotation == null) {
                    continue;
                }
                //获取属性的名称
                String fieldName = field.getName();
                //容器中获取属性对应的bean
                Object fieldObj = classMap.get(fieldName);
                //开启私有属性可写入通道
                field.setAccessible(true);
                //向类属性注入依赖的类对象值
                field.set(obj, fieldObj);
            }
        }
    }

    private void initBean(String packagePath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (StringUtils.isEmpty(packagePath)) {
            throw new RuntimeException("packagePath 注解包扫描路径不能为空！");
        }
        //扫描指定路径下的所有class文件，第二个参数为是否扫描路径的子文件夹
        List<String> clazzNameList = ClazzUtils.getClazzName(packagePath, true);
        if (clazzNameList == null || clazzNameList.isEmpty()) {
            log.info("指定包路径下没有找到任何类文件！");
            return;
        }
        //遍历所有的类
        for (String classPath : clazzNameList) {
            if (classPath.contains("IocTest")) {
                continue;
            }
            Class<?> aClass = Class.forName(classPath);
            //判断类上是否加了ExtServiceAnnotation注解
            ExtServiceAnnotation declaredAnnotation = aClass.getDeclaredAnnotation(ExtServiceAnnotation.class);
            String id = null;
            if (declaredAnnotation != null) {
                //获取类首字母小写的beanId
                id = getBeanId(aClass);
                //把map作为存放bean的容器，key：beanId，value：beanId对应的对象
                classMap.put(id, aClass.newInstance());
            }
        }
    }

    //获取类首字母小写的beanId
    private String getBeanId(Class<?> aClass) {
        String substring = aClass.getSimpleName();
        if (substring.endsWith("Impl")) {
            substring = substring.substring(0, substring.length() - 4);
        }
        char firstChar = Character.toLowerCase(substring.charAt(0));
        return new StringBuilder().append(firstChar).append(substring.substring(1)).toString();
    }

    public Object getBean(String beanId) {
        if (StringUtils.isEmpty(beanId)) {
            throw new RuntimeException("getBean 入参beanId不能为空！");
        }
        return classMap.get(beanId);
    }


}
